#include "PathFinder.h"
#include "core/heuristics.h"
#include "search/AStar.h"
#include "search/ThataStar.h"


PathFinder::PathFinder(void)
	:grid()
	,allowDiagonal()
	,tunnel()
	,findMode(eFindersMode_ThetaStar)
	,heuristic(eHeuristicMode_Manhattan)
	,finder()
	,recentlyPath()
{
}

// PathFinder::PathFinder( const char* mapPath,int8 blockVal )
// 	:grid()
// 	,allowDiagonal()
// 	,tunnel()
// 	,findMode(eFindersMode_ThetaStar)
// 	,heuristic(eHeuristicMode_Manhattan)
// 	,finder()
// 	,recentlyPath()
// {
// 	grid = new Grid();
// 	grid->initWithFile(mapPath,blockVal);
// }


PathFinder::~PathFinder(void)
{
	if(grid)
		delete grid;
	if (finder)
		delete finder;
	toClear.clear();
	if (recentlyPath)
		delete recentlyPath;
}

bool PathFinder::init( FindersMode fm,SearchMode sm,HeuristicMode hm,bool _tunnel )
{
	toClear.clear();

	findMode = fm;
	switch (findMode)
	{
	case eFindersMode_AStar:
		finder = new AStar();
		break;
	case eFindersMode_DIJKStar:
		break;
	case eFindersMode_ThetaStar:
		finder = new ThataStar();
		break;
	case eFindersMode_BFS:
		break;
	case eFindersMode_DFS:
		break;
	case eFindersMode_JPS:
		break;
	default:
		break;
	}
	if (sm==eSearchMode_Diagonal)
		allowDiagonal = true;
	else 
		allowDiagonal = false;
	heuristic = hm;
	tunnel = _tunnel;
	return true;
}

int PathFinder::getHeuristic( AStarNode* sn,AStarNode* en )
{
	switch (heuristic)
	{
	case eHeuristicMode_Manhattan:
		return manhattan(sn,en);

	case eHeuristicMode_Cardintcard:
		return cardintcard(sn,en);
	}

	return 0;
}


Path* PathFinder::getPath( int startX,int startY,int endX,int endY )
{
	if(recentlyPath)
		delete recentlyPath;
	recentlyPath = NULL;
	reset();

	if(!grid) return NULL;
	AStarNode* startNode = grid->getNodeAt(startX,startY);
	AStarNode* endNode = grid->getNodeAt(endX,endY);
	if(!startNode || !endNode) return NULL;
	AStarNode* _endNode = NULL;

	if (finder)
		_endNode = finder->calculatePath(this,startNode,endNode,toClear);

	if (_endNode)
	{
		recentlyPath = traceBackPath(_endNode,startNode);
		return recentlyPath;
	}

	return NULL;
}

Path* PathFinder::traceBackPath( AStarNode* endNode,AStarNode* startNode )
{
	Path* p = new Path();
	AStarNode* n = endNode;
	while(1)
	{
		if (n->parent)
		{
			p->addNode(n);
			n = n->parent;
		}
		else
		{
			p->addNode(startNode);
			p->reverse();
			return p;
		}
	}

	return NULL;
}

void PathFinder::reset()
{
	for (size_t i=0;i<toClear.size();++i)
	{
		toClear[i]->reset();
	}
	toClear.clear();
}

/*bool PathFinder::initWithLuaTable( lua_State* L,int width,int height,int blockVal,FindersMode fm,SearchMode sm,HeuristicMode hm,bool _tunnel )
{
	// get data from lua lable
	lua_getglobal(L,"map_table");
	if(!lua_istable(L,-1)) return false;


	int8** tb=NULL;
	tb = new int8*[height];

	for (int i=0;i<height;++i)
	{
		tb[i] = new int8[width];
		memset(tb[i],0,width*sizeof(int8));
	}

	for (int i=1; i<=height; ++i)
	{
		lua_pushnumber(L,i);
		lua_gettable(L,-2);
		for (int j=1;j<=width;++j)
		{
			lua_pushnumber(L,j);
			lua_gettable(L,-2);		
			int val = lua_tonumber(L,-1);
			tb[i-1][j-1] = (int8)val;
			lua_pop(L,1);
		}
		lua_pop(L,1);
	}

	this->init(fm,sm,hm,_tunnel);

	return true;
}*/

// void PathFinder::setMapData( int8** data,int block,int w,int h )
void PathFinder::setMapData(const char* data,int block,int w,int h )
{
	if (grid)
		delete grid;
	grid = NULL;

	grid = new Grid();
	grid->initWithTalbe(data,block,w,h);

}
